//////////////  comments  //////////

#include <iostream>
#include <map>
#include <vector>
#include "combined.h"
#include "command.h"
#include "commandTable.h"
#include "definitions.h"
#include "help.h"
#include "stringutil.h"
#include "timestamp.h"
#include "world.h"

// Command definitions for commands beginning with the letters G through M
// (Keep in alphabetical order... it's MUCH easier)
CmdGecho::CmdGecho( void ) {
	setName( "gecho" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( false );
	setTags( "gecho message broadcast" );
	addSyntax( "syntax: gecho <message>     {CDisplays <message> to all connected players" );
	addHelp( "Your message will appear in whatever color your \"\" describes." );
}

bool CmdGecho::execute(Character* character, const std::string& args ) {
	std::string message;

	message << "{" << character->getEcho() << args << "{x";
	World::Instance().broadcast( message );

	return true;
}

CmdGet::CmdGet( void ) {
	setName( "get" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "drop get give take put object" );
	addSyntax( "syntax: get <name>      {CPick up target object" );
}

bool CmdGet::execute(Character* character, const std::string& args ) {
	std::string charBuf, roomBuf;
	std::string arg1, arg2;
	Room* room = character->getRoom();
	Object* target = NULL;
	Object* container = NULL;

	split( args, arg1, arg2 );

	if ( arg2.empty() ) {
		if ( arg1 == "all" ) { // get all objects in room...
			for ( std::vector< Object* >::iterator it = room->getObjects().begin(); room->getObjects().size() != 0; it = room->getObjects().begin() ) {
				character->add( *it );
				room->drop( *it );
				roomBuf << "\n\r" << character->getName() << " gets " << (*it)->getShortDesc() << "{x.";
				charBuf << "\n\rYou get " << (*it)->getShortDesc() << "{x.";
			}
			room->send( roomBuf );
			character->Send( charBuf );
			return true;
		} else { // get an item from a container...
			if ( ( container = character->Creature::getObject( arg2 ) ) == NULL ) {
				character->Send( "You don't have " + arg2 + "." );
				return false;
			}
/*			if ( ( target = container->getItem( arg1 ) ) == NULL ) {
				character->Send( arg1 + " isn't in " + container->getShort() + ".\n\r" );
				return false;
			}*/
			character->Send( "{RFIXME" );
		}
	} else { // get a certain item from the room...
		if ( ( target = room->getObject( arg1 ) ) == NULL ) {
			character->Send( "You don't see that here." );
			return false;
		}
		room->drop( target );
		character->add( target );
		roomBuf << character->getName() << " picks up " << target->getShortDesc() << "{x.";
		charBuf << "You pick up " << target->getShortDesc() << "{x.";
		room->send( roomBuf );
		character->Send( charBuf );
		return true;
	}

	character->Send( "error\n\r" );
	return false;
}

CmdGive::CmdGive( void ) {
	setName( "give" );	
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "drop get give take put object" );
	addSyntax( "syntax: give <object> <target>     {CAttempt to give <object> to <target>" );
}

bool CmdGive::execute(Character* character, const std::string& args ) {
	std::string buf;
	std::string object_s;
	std::string target_s;
	Object* object = NULL;
	Character* target = NULL;

	split( args, object_s, target_s );

	if ( args.empty() || object_s.empty() || target_s.empty() ) {
		character->Send( "syntax: give <object> <target>" );
		return false;
	}

	if ( ( object = character->Creature::getObject( object_s ) ) == NULL ) {
		character->Send( "You don't have that item." );
		return false;
	}

	if ( ( target = character->getRoom()->getCharacter( target_s ) ) == NULL ) {
		character->Send( "They're not here." );
		return false;
	}

	character->drop( object );
	target->add( object );

	buf << character->getName() << " gives " << object->getShortDesc() << " to " << target->getName() << '.';
	character->getRoom()->send( buf );
	buf = "You give ";
	buf << object->getShortDesc() << " to " << target->getName() << ".";
	character->Send( buf );
	buf = character->getName();
	buf << " gives you " << object->getShortDesc() << ".";
	target->Send( buf );

	return true;
}

CmdGoto::CmdGoto( void ) {
	setName( "goto" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "goto poof" );
	addSyntax( "syntax: goto <vnum>     {CTransport yourself to Room <vnum>" );
	addSyntax( "        goto <name>     {CTransport yourself to Character or Mob <name>" );
	addHelp( "Given a string argument, \"goto\" will first search the list of" );
	addHelp( "currently connected characters for a match, then search through" );
	addHelp( "the list of mobs." );
}

bool CmdGoto::execute(Character* character, const std::string& args ) {
	Room* to = NULL;
	Room* from = character->getRoom();
	Creature* target = NULL;

	if ( args.empty() ) {
		character->Send( " >> \"goto\" transports you instantly to any room of your choosing.\n\r\n\rsyntax: goto <room vnum>\n\r        goto <character name>" );
		return false;
	}

	if ( isdigit( args[0] ) ) { // They gave a number...
		if ( ( to = World::Instance().getRoom( atoi( args.c_str() ) ) ) == NULL ) {
			character->Send( "That room does not exist." );
			return false;
		}
	} else if ( isalpha( args[0] ) ) { // They gave a name...
		if ( ( target = World::Instance().getCharacter( args ) ) != NULL ) {
			to = target->getRoom();
		} else {
			if ( ( target = World::Instance().getMob( args ) ) != NULL ) {
				to = target->getRoom();
			} else {
				character->Send( "That target could not be found." );
				return false;
			}
		}
	} else {
		character->Send( getSyntax() );
		return false;
	}

	if ( to == from ) {
		character->Send( "You're already there." );
		return false;
	}

	from->drop( character );
	if ( !character->getPoofout().empty() )
		from->send( character->getPoofout() );
	if ( !character->getPoofin().empty() )
		to->send( character->getPoofin() );
	character->setRoom( to );
	to->add( character );

	// Force the "look" Command...
	std::string empty;
	CmdLook commandLook;
	commandLook.execute( character, empty );

	return true;
}

CmdHelp::CmdHelp( void ) {
	setName( "help" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "help" );
	addSyntax( "syntax: help               {CDisplay general help info" );
	addSyntax( "        help <topic>       {CDisplay information matching the given subject" );
}

bool CmdHelp::execute(Character* character, const std::string& args ) {

	character->Send( World::Instance().getHelp( args, character->getLevel() ) );

	return true;
}

CmdInformation::CmdInformation( void ) {
	setName( "information" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "information server data" );
	addSyntax( "syntax: information     {CDisplays server data" );
	addHelp( "The information command gives a list containing information on the current" );
	addHelp( "server build and also statistical information on the amount of data stored" );
	addHelp( "by the server process." );
}

bool CmdInformation::execute(Character* character, const std::string& args ) {
	std::string buf;
	int areas = 0;
	int rooms = 0;
	int exits = 0;
	int characters = 0;
	int mobs = 0;
	int mob_instances = 0;
	int objects = 0;
	int object_instances = 0;
	int resets = 0;
	int helps = 0;
	int boards = 0;
	int notes = 0;

	areas = Area::numAreas;
	rooms = Room::numRooms;
	mobs = Mob::numMobs - World::Instance().getMobs().size();
	mob_instances = World::Instance().getMobs().size();
	objects  = Object::numObjects - World::Instance().getObjects().size();
	object_instances = World::Instance().getObjects().size();
	resets = Reset::numResets;
	helps = Help::numHelps;
	boards = Board::numBoards;
	notes = Note::numNotes;

	// exits...
	for ( std::map<std::string,Area*>::iterator a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it )
		for ( std::vector< Room* >::iterator r_it = (*a_it).second->getRooms().begin(); r_it != (*a_it).second->getRooms().end(); ++r_it )
			for ( unsigned u = 0; u < 6; ++u )
				if ( (*r_it)->getExit( u )->getThere() )
					exits++;

	characters = World::Instance().getCharacters().size();

	buf << "\t{!WGeneral Information{x\n\r\n\r";
	buf << "Server version: " << World::Instance().getVersion() << "\n\r";
	buf << "Compiled: " << __TIME__ << " on " << __DATE__ << "\n\r"; // These macros may not be portable.
	buf << "Booted: " << World::Instance().getBooted() << "\n\r";
	buf << "Character index: " << World::Instance().getIndex() << "\n\r";
	buf << "Characters online: " << characters << "\n\r";
	buf << "Areas: " << areas << "\n\r";
	buf << "Rooms: " << rooms << "\n\r";
	buf << "Exits: " << exits << "\n\r";
	buf << "-Mobs: (" << mobs << " types)\n\r";
	buf << "  Instances: " << mob_instances << "\n\r";
	buf << "-Objects: (" << objects << " types)\n\r";
	buf << "  Instances: " << object_instances << "\n\r";
	buf << "Resets: " << resets << "\n\r";
	buf << "Help files: " << helps << "\n\r";
	buf << "Boards: " << boards << "\n\r";
	buf << "Notes: " << notes << "\n\r";

	character->Send( buf );

	return true;
}

CmdInventory::CmdInventory( void ) {
	setName( "inventory" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "inventory get drop give take put" );
	addSyntax( "syntax: inventory      {CDisplays the items you currently hold." );
}

bool CmdInventory::execute(Character* character, const std::string& args ) {
	std::string buf;

	if ( character->getInventory().size() == 0 ) {
		character->Send( "Your inventory is empty." );
		return false;
	}

	buf << "You look at your inventory:\n\r";

	for ( std::vector< Object* >::iterator it = character->getInventory().begin(); it != character->getInventory().end(); ++it )
		buf << "  " << (*it)->getShortDesc() << "\n\r";

	character->Send( buf );
	return true;
}

CmdLook::CmdLook( void ) {
	setName( "look" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "look scan" );
	addSyntax( "syntax: look     {CGlance around the room." );
}

bool CmdLook::execute(Character* character, const std::string& args ) {
	std::string arg1, arg2;
	std::string buf;
	Room* room = NULL;

	split( args, arg1, arg2 );

	if ( arg1.empty() ) {
		// Show Room info (name, description, exits, etc)...
		room = character->getRoom();
		buf << "{g" << room->getName() << "{x" << " [ {y" << room->getVnum() << "{x ]\n\r";
		buf << '{' << room->getDescolor() << room->getDesc() << "{x\n\rExits: {B[ {W";
		if ( room->noExits() )
			buf << "{Rnone{x ";
		else
			for ( int x=0; x < 6; x++ )
				if ( room->getExit( x )->getThere() )
					buf << Exit::direction2string( x ) << ' ';
		buf << "{B]{x";
		// Show Characters...
		for ( std::vector< Character* >::iterator it = room->getCharacters().begin(); it != room->getCharacters().end(); ++it ) {
			if ( (*it) == character )
				continue;
			buf << "\n\r  " << (*it)->getName() << " is here mocking you.";
		}
		// Show mobs...
		for ( std::vector< Mob* >::iterator it = room->getMobs().begin(); it != room->getMobs().end(); ++it )
			buf << "\n\r  " << (*it)->getLongDesc();
		// Show objects...
		for ( std::vector< Object* >::iterator it = room->getObjects().begin(); it != room->getObjects().end(); ++it )
			buf << "\n\r  " << (*it)->getLongDesc();
	}
// LOOK IN <CONTAINER>
	character->Send( buf );

	return true;
}

CmdMedit::CmdMedit( void ) {
	setName( "medit" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "medit mlist mload mob" );
	addSyntax( "syntax: medit <vnum>         {CEdit the mob specified by vnum" );
	addSyntax( "        medit make <vnum>    {CCreate a mob with the given vnum, and edit it" );
	addSyntax( "        medit drop <vnum>    {CDelete the mob with the given vnum" );
}

bool CmdMedit::execute(Character* character, const std::string& args ) {
	std::string arg1, s_vnum;
	unsigned u_vnum = 0;
	Mob* mob = NULL;
	Area* area = NULL;
	split( args, arg1, s_vnum );
	arg1 = lowerString( trim( arg1 ) );

	// What's the vnum?
	if ( arg1 == "make" || arg1 == "drop" ) {
		if ( ( u_vnum = atoi( s_vnum.c_str() ) ) < START_VNUM ) {
			character->Send( "Invalid vnum." );
			return false;
		}
	} else {
		if ( ( u_vnum = atoi( arg1.c_str() ) ) < START_VNUM ) {
			character->Send( "Invalid vnum." );
			return false;
		}
	}
	// Get the Area that owns the vnum...
	if ( ( area = World::Instance().getParentArea( u_vnum ) ) == NULL ) {
		character->Send( "Invalid vnum." );
		return false;
	}
	// Does the user have permission to the given area?
	if ( !area->hasPermission( character ) ) {
		character->Send( "You don't have permission to that vnum." );
		return false;
	}
	// Retrieve the Mob specified by u_vnum...
	for ( std::vector< Mob* >::iterator m_it = area->getMobs().begin(); m_it != area->getMobs().end(); ++m_it )
		if ( (*m_it)->getVnum() == u_vnum )
			mob = *m_it;

	if ( arg1 == "make" ) {
		// Did we find the Mob?
		if ( mob ) {
			character->Send( "That mob already exists." );
			return false;
		}
		// Create the mob and send the Character to the Mob Editor...
		mob = area->addMob();
		mob->setVnum( u_vnum );
		mob->setStrHeight( "average" );
		mob->setStrWeight( "average" );
		character->setStatus( MEDIT );
		character->setMob( mob );
		character->Send( "Welcome to the Symphony Editor for Mobs (SEM)!\n\r\n\r\tMob created successfully." );
		return true;
	} else if ( arg1 == "drop" ) {
		// Did we find the Mob?
		if ( !mob ) {
			character->Send( "That mob doesn't exist." );
			return false;
		}
		// The Mob exists, and the Character has permission, so let's remove the Mob...
		if ( !area->drop( mob ) ) {
			character->Send( "That mob couldn't be deleted." );
			return false;
		}
		delete mob;
		mob = NULL;
		character->Send( "Mob deleted." );
		return true;
	} else {
		// Did we find the Mob?
		if ( !mob ) {
			character->Send( "That mob doesn't exist." );
			return false;
		}
		character->setStatus( MEDIT );
		character->setMob( mob );
		character->Send( "Welcome to the Symphony Editor for Mobs (SEM)!" );
		return true;
	}
}
/*
bool CmdMedit::execute(Character* character, const std::string& args ) {
	std::string arg1, s_vnum;
	unsigned u_vnum = 0;
	Mob* mob = NULL;
	Area* area = NULL;
	split( args, arg1, s_vnum );
	arg1 = lowerString( trim( arg1 ) );

	if ( arg1 == "make" ) {
		// What's the vnum?
		if ( ( u_vnum = atoi( s_vnum.c_str() ) ) < START_VNUM ) {
			character->Send( "Invalid vnum." );
			return false;
		}
		// Get the Area that owns the vnum...
		if ( ( area = World::Instance().getParentArea( u_vnum ) ) == NULL ) {
			character->Send( "Invalid vnum." );
			return false;
		}
		// Does the user have permission to the given area?
		if ( area->hasPermission( character->getId() ) ) {
			character->Send( "You don't have permission to that vnum." );
			return false;
		}
		// Does the Mob specified by u_vnum exist?
		for ( std::vector< Mob* >::iterator m_it = area->getMobs().begin(); m_it != area->getMobs().end(); ++m_it )
			if ( (*m_it)->getVnum() == u_vnum ) {
				character->Send( "That mob already exists." );
				return false;
			}
		// Everything looks okay... we can create the mob and send the Character to the Mob Editor...
		mob = area->addMob();
		mob->setVnum( u_vnum );
		mob->setStrHeight( "average" );
		mob->setStrWeight( "average" );
		character->setStatus( MEDIT );
		character->setMob( mob );
		character->Send( "Welcome to the Symphony Editor for Mobs (SEM)!\n\r\n\r\tMob created successfully." );
		return true;
	} else if ( arg1 == "drop" ) {
		// What's the vnum?
		if ( ( u_vnum = atoi( s_vnum.c_str() ) ) < START_VNUM ) {
			character->Send( "Invalid vnum." );
			return false;
		}
		// Get the Area that owns the vnum...
		if ( ( area = World::Instance().getParentArea( u_vnum ) ) == NULL ) {
			character->Send( "Invalid vnum." );
			return false;
		}
		// Does the user have permission to the given area?
		if ( area->hasPermission( character->getId() ) ) {
			character->Send( "You don't have permission to that vnum." );
			return false;
		}
		// Does the Mob specified by u_vnum exist?
		for ( std::vector< Mob* >::iterator m_it = area->getMobs().begin(); m_it != area->getMobs().end(); ++m_it )
			if ( (*m_it)->getVnum() == u_vnum )
				mob = *m_it;
		// Did we find the Mob?
		if ( mob == NULL ) {
			character->Send( "That mob doesn't exist." );
			return false;
		}
		// The Mob exists, and the Character has permission, so let's remove the Mob...
		if ( !area->drop( mob ) ) {
			character->Send( "That mob couldn't be deleted." );
			return false;
		}
		delete mob;
		mob = NULL;
		character->Send( "Mob deleted." );
		return true;
	} else {
		if ( ( u_vnum = atoi( arg1.c_str() ) ) < START_VNUM ) {
			character->Send( "Invalid vnum." );
			return false;
		}
		// Get the Area that owns the vnum...
		if ( ( area = World::Instance().getParentArea( u_vnum ) ) == NULL ) {
			character->Send( "Invalid vnum." );
			return false;
		}
		// Does the user have permission to the given area?
		if ( area->hasPermission( character->getId() ) ) {
			character->Send( "You don't have permission to that vnum." );
			return false;
		}
		// Does the Mob specified by u_vnum exist?
		for ( std::vector< Mob* >::iterator m_it = area->getMobs().begin(); m_it != area->getMobs().end(); ++m_it )
			if ( (*m_it)->getVnum() == u_vnum )
				mob = *m_it;
		// Did we find the Mob?
		if ( mob == NULL ) {
			character->Send( "That mob doesn't exist." );
			return false;
		}
		character->setStatus( MEDIT );
		character->setMob( mob );
		character->Send( "Welcome to the Symphony Editor for Mobs (SEM)!" );
		return true;
	}
}
*/
CmdMlist::CmdMlist( void ) {
	setName( "mlist" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "mlist medit mload mob" );
	addSyntax( "syntax: mlist               {CList all mobs" );
	addSyntax( "        mlist <string>      {CList all mobs containing string in their name" );
}

bool CmdMlist::execute(Character* character, const std::string& args ) {
	std::string input = trim( args );
	std::string buf;

	if ( input.empty() ) {
		// List all Mobs...
		for ( std::map<std::string,Area*>::iterator a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it )
			for ( std::vector< Mob* >::iterator m_it = (*a_it).second->getMobs().begin(); m_it != (*a_it).second->getMobs().end(); ++m_it )
				buf << "\n\r[ " << format( 5, (*m_it)->getVnum(), 'G' ) << " ] " << (*m_it)->getShortDesc() << "{x";
		if ( buf.empty() ) {
			character->Send( "No mobs to display." );
			return false;
		}
		character->Send( buf );
		return true;
	} else {
		// List all Mobs matching the given string in either their name or short description...
		for ( std::map<std::string,Area*>::iterator a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it )
			for ( std::vector< Mob* >::iterator m_it = (*a_it).second->getMobs().begin(); m_it != (*a_it).second->getMobs().end(); ++m_it )
				if ( strstr( (*m_it)->getName(), input ) || strstr( (*m_it)->getShortDesc(), input ) )
					buf << "\n\r[ " << format( 5, (*m_it)->getVnum(), 'G' ) << " ] " << (*m_it)->getShortDesc() << "{x";
		if ( buf.empty() ) {
			character->Send( "No mobs matching that string." );
			return false;
		}
		character->Send( buf );
		return true;
	}

	return false;
}
/*
CmdMload::CmdMload( void ) {
	setName( "mload" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( true );
	setTags( "mload medit mlist mob" );
	addSyntax( "syntax: mload <vnum>      {CLoad the given mob into the current room." );
}

bool CmdMload::execute(Character* character, const std::string& args ) {

	return false;
}*/
